/*
 * PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
 *
 * Authors: Sumana Srinivasan, NeXT Inc.;            sumana_srinivasan@next.com
 *          Terence Parr, Parr Research Corporation; parrt@parr-research.com
 *          Russell Quong, Purdue University;        quong@ecn.purdue.edu
 *
 * VERSION 1.2
 *
 * SOFTWARE RIGHTS
 *
 * This file is a part of the ANTLR-based C++ grammar and is free
 * software.  We do not reserve any LEGAL rights to its use or
 * distribution, but you may NOT claim ownership or authorship of this
 * grammar or support code.  An individual or company may otherwise do
 * whatever they wish with the grammar distributed herewith including the
 * incorporation of the grammar or the output generated by ANTLR into
 * commerical software.  You may redistribute in source or binary form
 * without payment of royalties to us as long as this header remains
 * in all source distributions.
 *
 * We encourage users to develop parsers/tools using this grammar.
 * In return, we ask that credit is given to us for developing this
 * grammar.  By "credit", we mean that if you incorporate our grammar or
 * the generated code into one of your programs (commercial product,
 * research project, or otherwise) that you acknowledge this fact in the
 * documentation, research report, etc....  In addition, you should say nice
 * things about us at every opportunity.
 *
 * As long as these guidelines are kept, we expect to continue enhancing
 * this grammar.  Feel free to send us enhancements, fixes, bug reports,
 * suggestions, or general words of encouragement at parrt@parr-research.com.
 * 
 * NeXT Computer Inc.
 * 900 Chesapeake Dr.
 * Redwood City, CA 94555
 * 12/02/1994
 * 
 * Restructured for public consumption by Terence Parr late February, 1995.
 *
 * DISCLAIMER: we make no guarantees that this grammar works, makes sense,
 *             or can be used to do anything useful.
 */
/* 2001-2002
 * Version 1.0
 * This C++ grammar file has been converted from PCCTS to run under 
 *  ANTLR to generate lexer and parser in C++ code by
 *  Jianguo Zuo and David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 *
 */
/* 2003
 * Version 2.0 was published by David Wigg in September 2003
 */
/* 2004
 * Version 3.0 July 2004
 * This is version 3.0 of the C++ grammar definition for ANTLR to 
 *  generate lexer and parser in C++ code updated by
 *  David Wigg at
 *  The Centre for Systems and Software Engineering
 *  London South Bank University
 *  London, UK.
 */
/* 2005
 * Version 3.1 November 2005
 * Updated by David Wigg at London South Bank University
 *
 */
/* 2007
 * Version 3.2 November 2007
 * Updated by David Wigg at London South Bank University
 *
 * wiggjd@bcs.ac.uk
 * blackse@lsbu.ac.uk
 *
 * See MyReadMe.txt for further information
 *
 * This file is best viewed in courier font with tabs set to 4 spaces
 */
 /* 2009
  * Version 3.3 June, 2009
  * Updated by Wilson Chen at HangZhou
  *
  * oeichenwei@yahoo.com
  */

header "pre_include_hpp"
	{// pre_include_hpp
	}

header "post_include_hpp"
	{// post_include_hpp
	}

header "pre_include_cpp"
	{// pre_include_cpp
	}

header "post_include_cpp"
	{// post_include_cpp
	}

header
	{
	// File generated from CPP_parser.g
	// Version 3.2 November 2007
	// This file is best viewed in courier font with tabs set to 4 spaces
	//
	// The statements in this block appear in both CPPLexer.hpp and CPPParser.hpp
	#include "antlr/CharScanner.hpp"
	#include "CPPDictionary.hpp"
	#include "data.h"
	#include "PNode.hpp"
	#include "PNodeFactory.hpp"

	// Following externs declared here to be available for users

	// Declared and set in CPPParser.cpp
	extern int lineNo; // current line
	extern bool in_user_file;	// true = in principal file, false = in an include file

	// Declared and set in CPPLexer.cpp
	extern bool in_user_file_deferred;

	extern int deferredLineCount;	// used to accumulate line numbers in comments etc.

	extern char principal_file[128];	// Name of user file
	extern int principal_line;		// Principal file's line number
	extern int principal_last_set;	// Where principal file's line number was last set
									//   in preprocessed *.i file

	extern char current_included_file[128];	// Name of current include file
	extern int include_line;		// Included file's line number
	extern int include_last_set;	// Where included file's line number was last set
									//   in preprocessed *.i file

	// The statements in this block appear in both CPPLexer.hpp and CPPParser.hpp
	}

options
	{
	language = "Cpp";
	}

{
// File generated from CPP_parser.g
// Version 3.2 November 2007
// This file is best viewed in courier font with tabs set to 4 spaces
//
//	The statements in this block appear only in CPPParser.cpp

int statementTrace = 2;	// Used to control selected (level) tracing (see support.cpp)
						// 1 Shows which external and member statements selected
						// 2 Shows above plus all declarations/definitions
						// 3 reserved for future use
						// 4 and above available for user

void CPPParser::init()
	{
	antlrTrace(false);	// This is a dynamic trace facility for use with -traceParser etc.
						// It requires modification in LLkParser.cpp and LLkParser.hpp
						//  (Copies of these modified files are supplied with this code)
						//  otherwise it should be commented out (see MyReadMe.txt)
						// true shows antlr trace (or can be set and reset during parsing)
						// false stops showing antlr trace 
						// Provided the parser is always generated with -traceParser this
						//  facility allows trace output to be turned on or off just by changing
						//  the setting here from false to true or vice versa and then
						//  recompiling and linking CPPParser only thus avoiding the need
						//  to use antlr.Tool to re-generate the lexer and parser again
						//  with (or without) -traceParser each time before recompiling. 
						// Antlr trace can also be turned on and off dynamically using
						//  antlrTrace_on or antlrTrace_off statements inserted into the
						//  source code being parsed (See antlrTrace_on and antlrTrace_off below).
					
	// Creates a dictionary to hold symbols with 4001 buckets, 200 scopes and 800,000 characters
	// These can be changed to suit the size of program(s) being parsed
	symbols = new CPPDictionary(4001, 200, 800000);

	// Set template parameter scope - Not used at present
	templateParameterScope = symbols->getCurrentScopeIndex();	// Set template parameter scope to 0

	symbols->saveScope();	// Advance currentScope from 0 to 1
	// Set "external" scope for all types
	externalScope = symbols->getCurrentScopeIndex();	// Set "external" scope to 1 for types

	// Declare predefined scope "std" in external scope
	CPPSymbol *a = new CPPSymbol("std", CPPSymbol::otTypedef);
	symbols->define("std", a);

	symbols->saveScope();	// Advance currentScope from 1 to 2 (and higher) for all other symbols
							//  treated as locals

	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_sc = scInvalid;	// For StorageClass
	_tq = tqInvalid;	// For TypeQualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_fs = fsInvalid;	// For FunctionSpecifier

	functionDefinition = 0;
	qualifierPrefix[0] = '\0';
	enclosingClass = "";
	assign_stmt_RHS_found = 0;
	in_parameter_list = false;
	K_and_R = false;	// used to distinguish old K & R parameter definitions
	in_return = false;
	is_address = false;
	is_pointer = false;
	}	// End of CPPParser::init()

int lineNo = 0;
bool in_user_file;	// true = in principal file, false = in an include file
					// Set from in_user_file_deferred by external_declaration in CPP_parser.g

//	The statements in this block appear only in CPPParser.cpp
}

class CPPParser extends Parser;

options
	{
	k = 2;
	exportVocab = STDC;
	buildAST = true;
	ASTLabelType = "RefPNode";
	codeGenMakeSwitchThreshold = 2;
	codeGenBitsetTestThreshold = 3;
	genHashLines = false;
	}

{	// These declarations go into CPPParser.hpp
public:
	#define CPPParser_MaxQualifiedItemSize 500

	// These codes are not stored with symbol names in CPPSymbol,
	//   but they are available for development
	// Can't bitwise-OR enum elements together, this must be an int; damn!
	typedef unsigned long TypeSpecifier;   // note: must be at least 16 bits
	#define tsInvalid   0x0
	#define tsVOID      0x1
	#define tsCHAR      0x2
	#define tsSHORT     0x4
	#define tsINT       0x8
	#define tsLONG      0x10
	#define tsFLOAT     0x20
	#define tsDOUBLE    0x40
	#define tsSIGNED    0x80
	#define tsUNSIGNED  0x100
	#define tsTYPEID    0x200
	#define tsSTRUCT    0x400
	#define tsENUM      0x800
	#define tsUNION     0x1000
	#define tsCLASS     0x2000
	#define tsWCHAR_T   0x4000
	#define tsBOOL      0x8000

	enum TypeQualifier 
		{ 
		tqInvalid=0, tqCONST=1, tqVOLATILE 
		};

	enum StorageClass 
		{
		scInvalid=0, scAUTO=1, scREGISTER,
		scSTATIC, scEXTERN, scMUTABLE
		};

	enum FunctionSpecifier 
		{
		fsInvalid=0,
		fsVIRTUAL, fsINLINE, fsEXPLICIT, fsFRIEND
		};

	typedef int QualifiedItem;
		#define qiInvalid     0x0
		#define qiType        0x1	// includes enum, class, typedefs, namespace
		#define qiDtor        0x2
		#define qiCtor        0x4
		#define qiOperator    0x8
		#define qiPtrMember   0x10
		#define qiVar         0x20
		#define qiFun         0x40

protected:
	// Symbol table management stuff
	CPPDictionary *symbols;
	int templateParameterScope;
	int externalScope;
	int anyType;
	int anyNonType;

	bool _td;			// For typedef
	bool _fd;			// For friend
	StorageClass _sc;	// For storage class
	TypeQualifier _tq;	// For type qualifier
	TypeSpecifier _ts;	// For type specifier
	FunctionSpecifier _fs;	// For declaration specifier
		
	int functionDefinition;	// 0 = Function definition not being parsed
							// 1 = Parsing function name
							// 2 = Parsing function parameter list
							// 3 = Parsing function block

	char qualifierPrefix[CPPParser_MaxQualifiedItemSize+1];
	char *enclosingClass;
	int assign_stmt_RHS_found;
	bool in_parameter_list;
	bool K_and_R;	// used to distinguish old K & R parameter definitions
	bool in_return;
	bool is_address;
	bool is_pointer;

	// Limit lookahead for qualifiedItemIs()
	enum 
		{ 
		MaxTemplateTokenScan = 200 
		};

public:
void init();

protected:
	// Semantic interface in Support.cpp; 
	// You could subclass and redefine these functions
	//  so you don't have to mess with the grammar itself.
	
	// Symbol stuff
	virtual int qualifiedItemIsOneOf(QualifiedItem qiFlags, int lookahead_offset=0);
	virtual QualifiedItem qualifiedItemIs(int lookahead_offset=0);
	virtual int skipTemplateQualifiers(int& kInOut);
	virtual int skipNestedParens(int& kInOut);
	virtual int scopedItem(int k=1);
	virtual int finalQualifier(const int k=1);
	virtual int isTypeName(const char *s);
	virtual int isClassName(const char *s);
	virtual void end_of_stmt();

	// Scoping stuff
	virtual void enterNewLocalScope();
	virtual void exitLocalScope();
	virtual void enterExternalScope();
	virtual void exitExternalScope();

	// Aggregate stuff
	virtual void classForwardDeclaration(const char *, TypeSpecifier, FunctionSpecifier);
	virtual void beginClassDefinition(const char *, TypeSpecifier);
	virtual void endClassDefinition();
	virtual void beginEnumDefinition(const char *);
	virtual void endEnumDefinition();
	virtual void enumElement(const char *);

	// Declaration and definition stuff
	virtual void declarationSpecifier(bool,bool,StorageClass,TypeQualifier,TypeSpecifier,FunctionSpecifier);
	virtual void beginDeclaration();
	virtual void endDeclaration();
	virtual void beginConstructorDeclaration(const char *);
	virtual void endConstructorDeclaration();
	virtual void beginDestructorDeclaration(const char *);
	virtual void endDestructorDeclaration();
	virtual void beginParameterDeclaration();
	virtual void beginFieldDeclaration();
	virtual void beginFunctionDefinition();
	virtual void endFunctionDefinition();
	virtual void functionParameterList();
	virtual void functionEndParameterList(const int def);
	virtual void beginConstructorDefinition();
	virtual void endConstructorDefinition();
	virtual void beginDestructorDefinition();
	virtual void endDestructorDefinition();

	// Declarator stuff
	virtual void declaratorID(const char *, QualifiedItem);	// This stores new symbol with its type.
	virtual void declaratorArray();
	virtual void declaratorParameterList(const int def);
	virtual void declaratorEndParameterList(const int def);

	// template stuff
	virtual void templateTypeParameter(const char *);
	virtual void beginTemplateDeclaration();
	virtual void endTemplateDeclaration();
	virtual void beginTemplateDefinition();
	virtual void endTemplateDefinition();
	virtual void beginTemplateParameterList();
	virtual void endTemplateParameterList();

	// exception stuff
	virtual void exceptionBeginHandler();
	virtual void exceptionEndHandler();
	virtual void panic(const char *);

	// myCode functions ready for overriding in MyCode subclass
	// Include application code functions here
	virtual void myCode_pre_processing(int, char *[]);
	virtual void myCode_post_processing();
	virtual void myCode_end_of_stmt();
	virtual void myCode_function_direct_declarator(const char *);
}

translation_unit
	:	{enterExternalScope();}
		(external_declaration)*  EOF
		{exitExternalScope();}
	;

//external_declaration	Note: These comment lines are provided to assist searching for productions
external_declaration
	{
	 data s;
	 lineNo = LT(1)->getLine();
	 K_and_R = false;
	 FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	 in_user_file = in_user_file_deferred;
	}
	:  
	(
		// Template explicit specialisation
		("template" LESSTHAN GREATERTHAN)=>
		{if(statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration template explicit-specialisation\n",LT(1)->getLine());
		}
		"template" LESSTHAN GREATERTHAN external_declaration
	|
		// All typedefs
		("typedef")=>
		(
			("typedef" "enum")=>
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Typedef enum type\n",LT(1)->getLine());
			}
			"typedef"! enum_specifier {_td = true;} (init_declarator_list)? SEMICOLON! {end_of_stmt();}
			{#external_declaration = #(#[MYTYPEDEF, "typedef"], #external_declaration);}
		|
			(declaration_specifiers function_declarator[0] SEMICOLON)=>	// DW 11/02/05 This may not be possible
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Typedef function type\n",LT(1)->getLine());
			}
			function_declaration
		|
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Typedef variable type\n",LT(1)->getLine());
			}
			declaration
		|
			("typedef" class_specifier)=>
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Typedef class type\n",LT(1)->getLine());
			}
			"typedef"! class_decl_or_def[fs] {_td = true;} (init_declarator_list)? SEMICOLON! {end_of_stmt();}
			{#external_declaration = #(#[MYTYPEDEF, "typedef"], #external_declaration);}
		)
	|	
		// Class template declaration or definition
		(template_head (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Templated class decl or def\n",LT(1)->getLine());
		}
		template_head (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON! {end_of_stmt();}	// declaration
		{#external_declaration = #(#[MYTEMPLATE, "templatepro"], #external_declaration);}
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Enum definition\n",LT(1)->getLine());
		}
		enum_specifier (init_declarator_list)? SEMICOLON! {end_of_stmt();}
		{#external_declaration = #(#[MYDECLAR, "declaration"], #external_declaration);}
	|
		// Destructor definition (templated or non-templated)
		((template_head)? dtor_head[1] LCURLY)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Destructor definition\n",LT(1)->getLine());
		}
		(template_head)? dtor_definition
		{#external_declaration = #(#[MYTEMPLATE, "templatepro"], #external_declaration);}
	|  
		// Constructor definition (non-templated)
		// JEL 4/3/96 Added predicate that works, once the
		// restriction is added that ctor cannot be virtual
		// and ctor_declarator uses a more restrictive id
		(	(options {warnWhenFollowAmbig = false;}:
			 ctor_decl_spec)?
			{qualifiedItemIsOneOf(qiCtor)}?
		)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Constructor definition\n",LT(1)->getLine());
		}
		ctor_definition
	|!  
		// User-defined type cast
		(("inline")? scope_override  conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Operator function\n",LT(1)->getLine());
		}
		(m:"inline")? s = sc:scope_override fc:conversion_function_decl_or_def 
		{
		 #external_declaration = #[MYFUNCTION, "convertor"];
		 if(#m != nullAST)
			#external_declaration->addChild(RefPNode(#(#[MY, "specifier"], #m)));
		 if(#sc != nullAST)
			#external_declaration->addChild(RefPNode(#sc));
 		 #external_declaration->addChild(RefPNode(#fc));
		}
	|   
		// Function declaration
		(declaration_specifiers function_declarator[0] SEMICOLON)=> 
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Function declaration\n",LT(1)->getLine());
		}
		function_declaration
	|
		// Function definition
		(declaration_specifiers	function_declarator[1] LCURLY)=> 
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Function definition\n",LT(1)->getLine());
		}
		function_definition
	|
		// Function definition with int return assumed
		(function_declarator[1] LCURLY)=> 
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Function definition without return type\n",LT(1)->getLine());
		}
		function_definition
	|
		// K & R Function definition
		(declaration_specifiers	function_declarator[1] declaration)=>
		{K_and_R = true;
		 if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration K & R function definition\n",LT(1)->getLine());
		}
		function_definition
	|
		// K & R Function definition with int return assumed
		(function_declarator[1] declaration)=>
		{K_and_R = true;
		 if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration K & R function definition without return type\n",LT(1)->getLine());
		}
		function_definition
	|
		// Class declaration or definition
		(("extern")? (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Class decl or def\n",LT(1)->getLine());
		}
		("extern"!)? (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON! {end_of_stmt();}
		{#external_declaration = #(#[MYDECLAR, "declaration"], #external_declaration);}
	|
		// Copied from member_declaration 31/05/07
		(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Declaration\n",LT(1)->getLine());
		}
		declaration
	|  
		// Templated functions and constructors matched here.
		{beginTemplateDeclaration();}
		template_head
		(  
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Templated class forward declaration\n",LT(1)->getLine());
			}
			declaration
		|  
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON)=> 
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Templated function declaration\n",LT(1)->getLine());
			}
			function_declaration
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Templated function definition\n",LT(1)->getLine());
			}
			function_definition
		|
			// Templated constructor definition
            // JEL 4/3/96 Added predicate that works once the
            // restriction is added that ctor cannot be virtual
			(	ctor_decl_spec 
				{qualifiedItemIsOneOf(qiCtor)}?
			)=>
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d external_declaration Templated constructor definition\n",LT(1)->getLine());
			}
			ctor_definition
		)
		{endTemplateDeclaration();}
		{#external_declaration = #(#[MYTEMPLATE, "templatepro"], #external_declaration);}
	|  
		// Namespace definition
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Namespace definition\n",LT(1)->getLine());
		}
		"namespace"! namespace_definition
	|	
		// Semicolon
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Semicolon\n",LT(1)->getLine());
		}
		SEMICOLON! {end_of_stmt();}
	|	
		// Anything else 
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d external_declaration Other Declaration\n",LT(1)->getLine());
		}
		declaration
	|	
		// The next two entries may be used for debugging
		// Use this statement in the source code to turn antlr trace on (See note above)
		"antlrTrace_on" {antlrTrace(true);}
	|
		// Use this statement in the source code to turn antlr trace off (See note above)
		"antlrTrace_off" {antlrTrace(false);}
	)
	;	// end of external_declaration

//namespace_definition
namespace_definition
	:
		(ns:ID{declaratorID((ns->getText()).data(),qiType);})?
		LCURLY! 
		{enterNewLocalScope();}
		(external_declaration)*
		{exitLocalScope();}
		RCURLY!
		{#namespace_definition = #(#[MYNAMESPACE, "namespace"], #namespace_definition);}
	;

//namespace_alias_definition
namespace_alias_definition
	{
	data qid;
	}
	:
		"namespace"
		ns2:ID {declaratorID((ns2->getText()).data(),qiType);}
		ASSIGNEQUAL qid = qualified_id SEMICOLON {end_of_stmt();} 
	;

//member_declaration
member_declaration
	{
	data q;
	lineNo = LT(1)->getLine();
	FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
	(
		// Template explicit specialisation
		("template" LESSTHAN GREATERTHAN)=>
		{if(statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Template explicit-specialisation\n",LT(1)->getLine());
		}
		"template" LESSTHAN GREATERTHAN member_declaration
	|
		// All typedefs
		("typedef")=>
		(
			("typedef" "enum")=>
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Typedef enum type\n",LT(1)->getLine());
			}
			"typedef" enum_specifier {_td = true;} (init_declarator_list)? SEMICOLON! {end_of_stmt();}
			{#member_declaration = #(#[MYTYPEDEF, "typedef"], #member_declaration);}
		|
			(declaration_specifiers function_declarator[0] SEMICOLON)=>	// DW 11/02/05 This may not be possible member declaration
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Typedef function type\n",LT(1)->getLine());
			}
			function_declaration
		|
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Typedef variable type\n",LT(1)->getLine());
			}
			declaration
		|
			("typedef" class_specifier)=>
			{if(statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Typedef class type\n",LT(1)->getLine());
			}
			"typedef" class_decl_or_def[fs] {_td = true;} (init_declarator_list)? SEMICOLON! {end_of_stmt();}
			{#member_declaration = #(#[MYTYPEDEF, "typedef"], #member_declaration);}
		)
	|	
		// Templated class declaration or definition
		(template_head (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Templated class decl or def\n",LT(1)->getLine());
		}
		template_head (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON! {end_of_stmt();}	// declaration
		{#member_declaration = #(#[MYTEMPLATE, "templatepro"], #member_declaration);}
	|  
		// Enum definition (don't want to backtrack over this in other alts)
		("enum" (ID)? LCURLY)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Enum definition\n",LT(1)->getLine());
		}
		enum_specifier (init_declarator_list)? SEMICOLON!	{end_of_stmt();}
		{#member_declaration = #(#[MYDECLAR, "declaration"], #member_declaration);}
	|
		// Constructor declarator
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[0] SEMICOLON!
		)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Constructor declarator\n",LT(1)->getLine());
		}
		ctor_decl_spec ctor_declarator[0] SEMICOLON! {end_of_stmt();}
		{#member_declaration = #(#[MYFUNCTION, "ctor"], #member_declaration);}
	|  
		// JEL Predicate to distinguish ctor from function
		// This works now that ctor cannot have VIRTUAL
		// It unfortunately matches A::A where A is not enclosing
		// class -- this will have to be checked semantically
		// Constructor definition
		(	ctor_decl_spec
			{qualifiedItemIsOneOf(qiCtor)}?
			ctor_declarator[1]
			(COLON        // DEFINITION :ctor_initializer
			|LCURLY       // DEFINITION (compound Statement) ?
			)
		)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Constructor definition\n",LT(1)->getLine());
		}
		ctor_definition 
	|  
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		// Destructor declaration
		(dtor_head[0] (ASSIGNEQUAL OCTALINT)? SEMICOLON)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Destructor declaration\n",LT(1)->getLine());
		}
		dtor_head[0] (ASSIGNEQUAL! OCTALINT!{astFactory->addASTChild(currentAST,#[MY, "pure"]);})? SEMICOLON! {end_of_stmt();}
		{#member_declaration = #(#[MYFUNCTION, "dtor"], #member_declaration);}
	|
		// No template_head allowed for dtor member
		// Backtrack if not a dtor (no TILDE)
		// Destructor definition
		(dtor_head[1] LCURLY!)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Destructor definition\n",LT(1)->getLine());
		}
		dtor_head[1] dtor_body
		{#member_declaration = #(#[MYFUNCTION, "dtor"], #member_declaration);}
	|
		// Function declaration
		(declaration_specifiers	function_declarator[0] SEMICOLON)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Function declaration\n",LT(1)->getLine());
		}
		function_declaration
	|  
		// Function definition
		(declaration_specifiers function_declarator[1] LCURLY)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Function definition\n",LT(1)->getLine());
		}
		function_definition
	|!  
		// User-defined type cast
		(("inline")? conversion_function_decl_or_def)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Operator function\n",LT(1)->getLine());
		}
		(m:"inline")? fc:conversion_function_decl_or_def
		{
		 #member_declaration = #[MYFUNCTION, "convertor"];
		 if(#m != nullAST)
			#member_declaration->addChild(RefPNode(#(#[MY, "specifier"], #m)));
 		 #member_declaration->addChild(RefPNode(#fc));
		}
	|  
		// Hack to handle decls like "superclass::member",
		// to redefine access to private base class public members
		// Qualified identifier
		(qualified_id SEMICOLON)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Qualified ID\n",LT(1)->getLine());
		}
		q = qualified_id SEMICOLON {end_of_stmt();}
	|
		// Class declaration or definition
		(("friend")? (fs = function_specifier)* class_specifier)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Class decl or def\n",LT(1)->getLine());
		}
		("friend"!)? (fs = function_specifier)* class_decl_or_def[fs] (init_declarator_list)? SEMICOLON! {end_of_stmt();}
		{#member_declaration = #(#[MYDECLAR, "declaration"], #member_declaration);}
	|  
		(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Declaration\n",LT(1)->getLine());
		}
		declaration
	|  
		// Member without a type (I guess it can only be a function declaration or definition)
		((fs = function_specifier)* function_declarator[0] SEMICOLON)=>
		{fprintf(stderr,"%d warning Function declaration found without return type\n",LT(1)->getLine());
		 if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Function declaration\n",LT(1)->getLine());
		}
		(fs = function_specifier)* function_declarator[0] SEMICOLON! {end_of_stmt();}
		{#member_declaration = #(#[MYFUNCTION, "function"], #member_declaration);}
	|
		// Member without a type (I guess it can only be a function definition)
		((fs = function_specifier)* function_declarator[1] LCURLY)=>
		{fprintf(stderr,"%d warning Function definition found without return type\n",LT(1)->getLine());
		 if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Function definition without return type\n",LT(1)->getLine());
		}
		(fs = function_specifier)* function_declarator[1] compound_statement {endFunctionDefinition();}
		{#member_declaration = #(#[MYFUNCTION, "function"], #member_declaration);}
	|  
		// Templated functions and constructors matched here.
		{beginTemplateDeclaration();}
		template_head
		(  
			// templated forward class decl, init/decl of static member in template
			(declaration_specifiers (init_declarator_list)? SEMICOLON)=>
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated forward declaration\n",LT(1)->getLine());
			}
			declaration
		|
			// Templated function declaration
			(declaration_specifiers function_declarator[0] SEMICOLON)=>
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated function declaration\n",LT(1)->getLine());
			}
			function_declaration
		|  
			// Templated function definition
			(declaration_specifiers function_declarator[1] LCURLY)=> 
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated function definition\n",LT(1)->getLine());
			}
			function_definition
		|
			// Templated constructor declarator
			(	ctor_decl_spec
				{qualifiedItemIsOneOf(qiCtor)}?
				ctor_declarator[0] SEMICOLON
			)=>
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated constructor declarator\n",LT(1)->getLine());
			}
			ctor_decl_spec ctor_declarator[0] SEMICOLON {end_of_stmt();}
		|
			// Templated constructor definition
			// JEL 4/3/96 Added predicate that works once the
			// restriction is added that ctor cannot be virtual
			(ctor_decl_spec {qualifiedItemIsOneOf(qiCtor)}?
			)=>
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated constructor definition\n",LT(1)->getLine());
			}
			ctor_definition
		|!
			// Templated operator function
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated operator function\n",LT(1)->getLine());
			}
			(mt:"inline")? fct:conversion_function_decl_or_def
			{
			 #fct = #(#[MYFUNCTION, "convertor"], #fct);
	 		 if(#mt != nullAST)
				#fct->addChild(RefPNode(#(#[MY, "specifier"], #mt)));
			 astFactory->addASTChild(currentAST, ANTLR_USE_NAMESPACE(antlr)RefAST(#fct));
			}
		|
			// Templated class definition
			{if (statementTrace>=1) 
				OUTPUT_DEBUG("%d member_declaration Templated class definition\n",LT(1)->getLine());
			}
			class_head declaration
		)
		{endTemplateDeclaration();}
		{#member_declaration = #(#[MYTEMPLATE, "templatepro"], #member_declaration);}
	|!
		// Access specifier  
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Access specifier\n",LT(1)->getLine());
		}
		access_specifier COLON
	|
		// Semicolon
		{if (statementTrace>=1) 
			OUTPUT_DEBUG("%d member_declaration Semicolon\n",LT(1)->getLine());
		}
		SEMICOLON {end_of_stmt();}
	|	
		// The next two entries may be used for debugging
		// Use this statement in the source code to turn antlr trace on (See note above)
		"antlrTrace_on" {antlrTrace(true);}
	|
		// Use this statement in the source code to turn antlr trace off (See note above)
		"antlrTrace_off" {antlrTrace(false);}
	)
	;	// end member_declaration

//function_definition
function_definition
	:
	(	// Next line is equivalent to guarded predicate in PCCTS
		// (SCOPE | ID)? => <<qualifiedItemIsOneOf(qiType|qiCtor)>>?
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
		declaration_specifiers function_declarator[1]
		(	options{warnWhenFollowAmbig = false;}:
			({lineNo = LT(1)->getLine();} declaration)*	// Possible for K & R definition
			{in_parameter_list = false;}
		)?
		compound_statement
	|	
		function_declarator[1]
		(	options{warnWhenFollowAmbig = false;}:
			({lineNo = LT(1)->getLine();} declaration)*	// Possible for K & R definition
			{in_parameter_list = false;}
		)?
		compound_statement
	)
	{#function_definition = #(#[MYFUNCTION, "function"], #function_definition);}
	{endFunctionDefinition();}
	;

//declaration
declaration
	:	
	(	("extern" StringLiteral)=>
		linkage_specification
	|	
		simple_declaration
	|	
		using_statement
	)
	{
	 if(_td==true)
		#declaration = #(#[MYTYPEDEF, "typedef"], #declaration);
	 else
		#declaration = #(#[MYDECLAR, "declaration"], #declaration);
	}
	;

//linkage_specification
linkage_specification
	:	
		"extern"
		StringLiteral
		(LCURLY (external_declaration)* RCURLY
		|declaration
		)
	;

//class_head
class_head
	:	// Used only by predicates
		("struct"  
		|"union" 
		|"class" 
		)
		(ID	
			(LESSTHAN template_argument_list GREATERTHAN)?
			(base_clause)? 
		)? 
		LCURLY!
	;

//declaration_specifiers
declaration_specifiers
	{// Locals
	bool td = false;	// For typedef
	bool fd = false;	// For friend
	StorageClass sc = scInvalid;	// auto,register,static,extern,mutable
	TypeQualifier tq = tqInvalid;	// const,volatile	// aka cv_qualifier See type_qualifier
	TypeSpecifier ts = tsInvalid;	// char,int,double, etc., class,struct,union
	FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
	{
	// Global flags to allow for nested declarations
	_td = false;		// For typedef
	_fd = false;		// For friend
	_sc = scInvalid;	// For StorageClass		// auto,register,static,extern,mutable
	_tq = tqInvalid;	// For TypeQualifier	// aka cv_qualifier See type_qualifier
	_ts = tsInvalid;	// For TypeSpecifier
	_fs = fsInvalid;	// For FunctionSpecifier	// inline,virtual,explicit

	}
	(	
		specifier_prefix[td, fd, sc,tq,fs]
		ts = type_specifier
		(tq = type_qualifier)*		// const,volatile	// aka cv_qualifier See type_qualifier
	)
	{declarationSpecifier(td,fd,sc,tq,ts,fs);}
	;

//specifier_prefix
specifier_prefix [bool& td, bool& fd, StorageClass& sc, TypeQualifier& tq, FunctionSpecifier& fs]
	:
		(options {warnWhenFollowAmbig = false;}
		:	"typedef"!	{td=true;}			
		|	"friend"!	{fd=true;}
		|	sc = storage_class_specifier	// auto,register,static,extern,mutable
		|	tq = type_qualifier		// const,volatile	// aka cv_qualifier See type_qualifier
		|	fs = function_specifier	// inline,virtual,explicit
		|	("_declspec"!|"__declspec"!) LPAREN! ID RPAREN! 
		)*
		{
		 if(#specifier_prefix != nullAST)
			#specifier_prefix = #(#[MY, "specifier"], #specifier_prefix);
		}
	;

//storage_class_specifier
storage_class_specifier returns [CPPParser::StorageClass sc = scInvalid]
	:	"auto"		{sc = scAUTO;}
	|	"register"	{sc = scREGISTER;}
	|	"static"	{sc = scSTATIC;}
	|	"extern"	{sc = scEXTERN;}
	|	"mutable"	{sc = scMUTABLE;}
	;
		
//function_specifier
function_specifier returns [CPPParser::FunctionSpecifier fs = fsInvalid]
	:	("inline"|"_inline"|"__inline")	{fs = fsINLINE;}
	|	"virtual"						{fs = fsVIRTUAL;}
	|	"explicit"						{fs = fsEXPLICIT;}
	{#function_specifier = #(#[MY, "specifier"], #function_specifier);}
	;

//type_specifier
type_specifier returns [CPPParser::TypeSpecifier ts = tsInvalid]
	{//char *s;
	 TypeQualifier tq = tqInvalid;
	}
	:	
		ts = simple_type_specifier
	;

//simple_type_specifier
simple_type_specifier returns [CPPParser::TypeSpecifier ts = tsInvalid]
	{
	data s;
	ts = tsInvalid;
	}
	:	(
			{qualifiedItemIsOneOf(qiType|qiCtor)}?
			 s = qualified_type
			{#simple_type_specifier = #(#[MYTYPE, "type"],#simple_type_specifier);}
		|
			("typename"|"enum"|ts = class_specifier) 
			 s = qualified_type
			{declaratorID(s.c_str(),qiType);}	// This stores typename name in dictionary
			{#simple_type_specifier = #(#[MYTYPE, "typename"],#simple_type_specifier);}
		|	
			(	"char"		{ts |= tsCHAR;}
			|	"wchar_t"	{ts |= tsWCHAR_T;}  
			|	"bool"		{ts |= tsBOOL;}
			|	"short"		{ts |= tsSHORT;}
			|	"int"		{ts |= tsINT;}
			|	("_int8"|"__int8")		{ts |= tsINT;}
			|	("_int16"|"__int16")	{ts |= tsINT;}
			|	("_int32"|"__int32")	{ts |= tsLONG;}
			|	("_int64"|"__int64")	{ts |= tsLONG;}
			|	("_w64"|"__w64")		{ts |= tsLONG;}
			|	"long"		{ts |= tsLONG;}
			|	"signed"	{ts |= tsSIGNED;}
			|	"unsigned"	{ts |= tsUNSIGNED;}
			|	"float"		{ts |= tsFLOAT;}
			|	"double"	{ts |= tsDOUBLE;}
			|	"void"		{ts |= tsVOID;}
			)+
			{#simple_type_specifier = #(#[MYTYPE, "basictype"],#simple_type_specifier);}
		)
	;

//qualified_type
qualified_type! returns [data qit] 
	{
	 data so = NULL;
	 char qitem01[CPPParser_MaxQualifiedItemSize+1];
	 qitem01[0] = '\0';
	}
	: 
		// JEL 3/29/96 removed this predicate and moved it upwards to
		// simple_type_specifier.  This was done to allow parsing of ~ID to 
		// be a unary_expression, which was never reached with this 
		// predicate on
		// {qualifiedItemIsOneOf(qiType|qiCtor)}?

		so = scope_override 
		{
		 strcpy(qitem01, so.c_str());
		}
		id:ID 
		{
		 strcat(qitem01, (id->getText()).data());
		 qit = qitem01;
		}
		(options {warnWhenFollowAmbig = false;}:
		 m:LESSTHAN template_argument_list GREATERTHAN{#m=#(#[MY, "template"], returnAST);}
		)?
		{#qualified_type = #(id, m);}
	;

//class_specifier
class_specifier returns [CPPParser::TypeSpecifier ts = tsInvalid]
	:	
		("class"	{ts = tsCLASS;}	
		|"struct"	{ts = tsSTRUCT;}
		|"union"	{ts = tsUNION;}
		)
	;

//type_qualifier
type_qualifier returns [CPPParser::TypeQualifier tq = tqInvalid] // aka cv_qualifier
	:  
		("const"	{tq = tqCONST;} 
		|"volatile"	{tq = tqVOLATILE;}
		)
	;

//class_prefix
class_prefix
	:
	(("_declspec"!|"__declspec"!) LPAREN! expression RPAREN!)*
	{
	 if(#class_prefix != nullAST)
		#class_prefix = #(#[MY, "specifier"], #class_prefix);
	}
	;
	
//class_decl_or_def
class_decl_or_def [FunctionSpecifier fs] 
	{char *saveClass; 
	 data id;
	 data typeName;
	 char qid[CPPParser_MaxQualifiedItemSize+1];
	 TypeSpecifier ts = tsInvalid;	// Available for use
	}
	:	
		("class"!	{ts = tsCLASS;typeName="class";}	
		|"struct"!	{ts = tsSTRUCT;typeName="class";}
		|"union"!	{ts = tsUNION;typeName="union";}
		)
		class_prefix	// Temp for Evgeniy
		(	id = qualified_id
			{strcpy(qid,id.c_str());}
			(options{generateAmbigWarnings = false;}:
				(SEMICOLON|member_declarator)=>
				// Empty 
				{classForwardDeclaration(qid, ts, fs);}	// This stores class name in dictionary
			|
				(base_clause)?
				LCURLY!
				{saveClass = enclosingClass; enclosingClass = symbols->strdup(qid);
				 beginClassDefinition(qid, ts);}	// This stores class name in dictionary
				(member_declaration)*
				{endClassDefinition();}
				RCURLY!
				{enclosingClass = saveClass;}
			)
		|
			LCURLY!
			{saveClass = enclosingClass; enclosingClass = "__anonymous";
			 beginClassDefinition("anonymous", ts);}	// This stores "anonymous" name in dictionary
			(member_declaration)*
			{endClassDefinition();}
			RCURLY!
			{enclosingClass = saveClass;}
		)
		{#class_decl_or_def = #(#[MYCLASS, typeName.c_str()], #class_decl_or_def);}
	;

//base_clause
base_clause
	:	
		COLON! base_specifier (COMMA! base_specifier)*
		{#base_clause = #(#[MY, "baseclass"], #base_clause);}
	;

//base_specifier
base_specifier!
	{data qt;}
	:	
		(	v:"virtual" s:(access_specifier{#s=returnAST;})? qt = q:qualified_type{#q=returnAST;} 
		|	access_specifier{#s=returnAST;} (v2:"virtual")? qt = qualified_type{#q=returnAST;}
		|	qt = qualified_type{#q=returnAST;}
		)
		{#base_specifier = #(#[MYTYPE, "typename"], q, #(#[MY, "specifier"], v, v2, s));}
	;

//access_specifier
access_specifier
	:	
		(	"public"
		|	"protected"
		|	"private"
		)
	;

//enum_specifier
enum_specifier
	{
	data id;
	}
	:	
		"enum"!
		(	
			LCURLY! enumerator_list RCURLY!
		|	
			id = qualified_id
			{beginEnumDefinition(id.c_str());}	// This stores id name as an enum type in dictionary
			(LCURLY! enumerator_list RCURLY!)?
			{endEnumDefinition();}
		)
		{#enum_specifier = #(#[MYENUM, "enum"], #enum_specifier);}
	;

//enumerator_list
enumerator_list
	:	
		enumerator (COMMA! (enumerator)? )*	// Allows comma at end of list
	;

//enumerator
enumerator!
	:	
		id:ID (ASSIGNEQUAL! constant_expression{#id->addChild(RefPNode(#(#[MY, "assign"], returnAST)));})?
		{enumElement((id->getText()).data());}	// This stores id name in dictionary
		{#enumerator = #id;}
	;

/* This matches a generic qualified identifier ::T::B::foo
 * (including OPERATOR).
 * It might be a good idea to put T::~dtor in here
 * as well, but id_expression in expr.g puts it in manually.
 * Maybe not, 'cause many people use this assuming only A::B.
 * How about a 'qualified_complex_id'?
 */
//qualified_id
qualified_id returns [data qid]
	{
	data so = NULL;
	data op = NULL;
	char qitem02[CPPParser_MaxQualifiedItemSize+1];
	qitem02[0] = '\0';
	}
	:	
		so =  scope_override
		{
		 strcpy(qitem02, so.c_str());
		}
		(	id:ID {strcat(qitem02,(id->getText()).data());}
			((LESSTHAN template_argument_list GREATERTHAN)=>
			  LESSTHAN template_argument_list GREATERTHAN)? // {strcat(qitem02,"<...>");}
		|  
			OPERATOR! op=optor
			{strcat(qitem02,"operator"); strcat(qitem02,op.c_str());}
		|
			TILDE id_expression		// 1/08/07
		|
			"typeid" {strcat(qitem02, "typeid");}	//Add typeid here to treat typeid as a function, Wilson Chen,14/7/09, See also postfix_expression
		)
		{
		qid = qitem02;
		}
	;

//typeID
typeID
	:	
		{isTypeName((LT(1)->getText()).data())}?
		ID
	;

//init_declarator_list
init_declarator_list
	:	
		member_declarator (COMMA! member_declarator)*
	;

//member_declarator
member_declarator!
	:	
		((ID)? COLON constant_expression)=>m:(ID{#m=#(ID);})? COLON v:(constant_expression{#v=#(#[MY, "bytes"], returnAST);})
		{#member_declarator = #(#[MY, "variables"], m, v);}
	|  
		d:declarator{#d=returnAST;}
		(
			(ASSIGNEQUAL OCTALINT)=>ASSIGNEQUAL i:OCTALINT	// The value must be zero (for pure virtual)
			{#i=#(#[MY,"assign"], #i);}
		|	
			ASSIGNEQUAL 
			initializer{#i=#(#[MY,"assign"], returnAST);}
		|	
			LPAREN expression_list RPAREN{#i=#(#[MY, "ctor"], returnAST);}
		)?
		{
		 if(_td==true)
			#member_declarator = #(#[MY,"newtype"], d, i);
		 else
			#member_declarator = #(#[MY,"variables"], d, i);
		}
	;

//initializer
initializer
	:	
		remainder_expression	// assignment_expression
	|	
		LCURLY! initializer (COMMA! (initializer)? )* RCURLY!	// Allows comma at end of list
		{#initializer = #(#[MY, "values"], #initializer);}
	;

//declarator
declarator
	:
	!	(ptr_operator)=> pt:ptr_operator	// AMPERSAND or STAR etc.
		d:declarator
		{#d->addChild(#pt); #declarator = #d;}
	|	
		direct_declarator
	;

//direct_declarator
direct_declarator
	{
	data id;
	int nType = 0;
	}
	:	
		(qualified_id LPAREN (RPAREN|declaration_specifiers) )=>	// Must be function declaration
		function_inline_declarator
	|	
		(qualified_id LPAREN qualified_id)=>	// Must be class instantiation
		id = qualified_id
		{declaratorID(id.c_str(),qiVar);}
		LPAREN
		expression_list
		RPAREN
	|
	!	(qualified_id LSQUARE)=>	// Must be array declaration
		id = QID:qualified_id{#QID=returnAST;}
		{if (_td==true)       // This statement is a typedef   
			declaratorID(id.c_str(),qiType);	// This statement is a typedef
		 else
			declaratorID(id.c_str(),qiVar);
		 is_address = false; is_pointer = false;
		}
		(options {warnWhenFollowAmbig = false;}:
		 LSQUARE! (constant_expression{astFactory->addASTChild(currentAST,ANTLR_USE_NAMESPACE(antlr)RefAST(returnAST));})? RSQUARE!)+
		{declaratorArray();}
		{#direct_declarator=#(QID, #(#[MY, "array"], currentAST.root));}
	|
		(qualified_id RPAREN LPAREN)=>	// Must be function declaration (see function_direct_declarator)
		id = qualified_id
		{if (_td==true)       // This statement is a typedef   
			declaratorID(id.c_str(),qiType);	// This statement is a typedef
		 else
			declaratorID(id.c_str(),qiFun);
		 is_address = false; is_pointer = false;
		}
	|
		id = qualified_id
		{
		if (_td==true)
			{
			declaratorID(id.c_str(),qiType);	// This statement is a typedef
			}
		 else
			declaratorID(id.c_str(),qiVar);
		 is_address = false; is_pointer = false;
		}
	|!	
		LPAREN! d:declarator RPAREN! 
		(options {warnWhenFollowAmbig = false;}:
		 nType=s:declarator_suffix)? // DW 1/9/04 declarator_suffix made optional as failed on line 2956 in metrics.i
							 // According to the grammar a declarator_suffix is not required here
		{
		 if(nType == 1)
		 {
			#d->addChild(#s);
			#direct_declarator = #d;
		 }
		 else if(nType == 2)
			#direct_declarator = #(#[MYFUNCTION, "function"], #d, #s);
		 else
			#direct_declarator = #d;
		}
	;

//declarator_suffix
declarator_suffix returns [int nType = 0]		// Note: Only used above in direct_declarator
	{CPPParser::TypeQualifier tq;}  
	:
	(	
		//(options {warnWhenFollowAmbig = false;}:
		(LSQUARE! (constant_expression)? RSQUARE!)+
		{declaratorArray();nType=1;}
		{#declarator_suffix=#(#[MY, "array"], #declarator_suffix);}
	|	
		{(!((LA(1)==LPAREN)&&(LA(2)==ID))||(qualifiedItemIsOneOf(qiType|qiCtor,1)))}?
		LPAREN! {declaratorParameterList(0);}
		(parameter_list)?
		RPAREN! {declaratorEndParameterList(0);}
		(tq = type_qualifier)*
		(exception_specification)?
		{nType = 2;}
	)
	;

//conversion_function_decl_or_def
conversion_function_decl_or_def
	{CPPParser::TypeQualifier tq;}
	:	
		OPERATOR! declaration_specifiers conversion_type_modifier 
		(LESSTHAN! template_parameter_list GREATERTHAN!)?
		LPAREN! (parameter_list)? RPAREN!	
		(tq = type_qualifier)*	// DW 29/07/05 ? changed to *
		(exception_specification)?
		(	compound_statement
		|	SEMICOLON! {end_of_stmt();}
		)
	;

//conversion_type_modifier
conversion_type_modifier
	:
	(STAR | AMPERSAND)?	// DW 01/08/03 Use type_specifier here? see syntax
	{#conversion_type_modifier = #(#[MY, "modifier"], #conversion_type_modifier);}
	;

//function_declaration
function_declaration
	{
	bool bTypeDef = false;
	}
	:
	declaration_specifiers{bTypeDef=_td;} function_declarator[0] SEMICOLON! {end_of_stmt();}
	{
	 if(bTypeDef)
		#function_declaration = #(#[MYTYPEDEF, "typedef"], #(#[MYFUNCTION, "function"], #function_declaration));
	 else
		#function_declaration = #(#[MYFUNCTION, "function"], #function_declaration);
	}
	;

 //function_declarator
function_declarator [int definition]
	:	
		(ptr_operator)=> ptr_operator function_declarator[definition]
	|	
		function_direct_declarator[definition]
	;

//function_direct_declarator
function_direct_declarator [int definition] 
	{
	data q;
	CPPParser::TypeQualifier tq;
	}
	:
		(	// fix prompted by (isdigit)() in xlocnum
			LPAREN! 
			declarator
			RPAREN!
		|
			q = qualified_id
			{
			declaratorID(q.c_str(),qiFun);
			}
		)

		{		
#ifdef MYCODE
		if (definition)
			myCode_function_direct_declarator(q.c_str());
#endif MYCODE
		}

		LPAREN !
		{
		functionParameterList();
		if (K_and_R == true)
			in_parameter_list = false;
		else
			in_parameter_list = true;
		}
		(parameter_list)? 
		{
		if (K_and_R == true)
	  		in_parameter_list = true;
		else
			in_parameter_list = false;
		}
		RPAREN !
		(options{warnWhenFollowAmbig = false;}:
		 tq = type_qualifier)*
		(ASSIGNEQUAL! OCTALINT!{astFactory->addASTChild(currentAST,#[MY, "pure"]);})?	// The value of the octal must be 0, pure virtual function
		{functionEndParameterList(definition);}
		(exception_specification)? 
	;

//function_inline_declarator
function_inline_declarator
	{
	data id;
	CPPParser::TypeQualifier tq;
	}
	:
		id = qualified_id
		{if (_td==true)       // This statement is a typedef   
			declaratorID(id.c_str(),qiType);
		 else
			declaratorID(id.c_str(),qiFun);
		}
		LPAREN! {declaratorParameterList(0);}
		(parameter_list)?
		RPAREN! {declaratorEndParameterList(0);}
		(tq = type_qualifier)*
		(exception_specification)?
		{#function_inline_declarator = #(#[MYFUNCTION, "function"], #function_inline_declarator);}
	;

//dtor_definition
dtor_definition
	:
		dtor_head[1] dtor_body
		{#dtor_definition = #(#[MYFUNCTION, "dtor"], #dtor_definition);}
	;

//ctor_definition
ctor_definition 
	:
		ctor_head
		ctor_body
		{endConstructorDefinition();}
		{#ctor_definition = #(#[MYFUNCTION, "ctor"], #ctor_definition);}
	;

//ctor_head
ctor_head 
	:
		ctor_decl_spec
		ctor_declarator[1]
	;

//ctor_decl_spec
ctor_decl_spec
	:
		(("inline"|"_inline"|"__inline")|"explicit")*
	;

//ctor_declarator
ctor_declarator[int definition]
	{data q;}
	: 
		q = qualified_ctor_id
		{declaratorParameterList(definition);}
		LPAREN! (parameter_list)? RPAREN!
		{declaratorEndParameterList(definition);}
		(exception_specification)?
	;

// This matches a generic qualified identifier ::T::B::foo
// that is satisfactory for a ctor (no operator, no trailing <>)
qualified_ctor_id returns [data q]
	{
	data so;
	char qitem03[CPPParser_MaxQualifiedItemSize+1];
	qitem03[0] = '\0';
	}
	: 
		so = scope_override
		{strcpy(qitem03, so.c_str());}
		id:ID	// DW 24/05/04 Note. Neither Ctor or Dtor recorded in dictionary
		{strcat(qitem03,(id->getText()).data());
		q = qitem03;
		//OUTPUT_DEBUG("CPP_parser.g qualified_ctor_id q %s\n",q);
		} 
	;

//ctor_body
ctor_body
	:
		(ctor_initializer)?
		compound_statement
	;

//ctor_initializer
ctor_initializer
	:
		COLON! superclass_init (COMMA! superclass_init)*
		{#ctor_initializer = #(#[MY, "ctorinit"], #ctor_initializer);}
	;

//superclass_init
superclass_init!
	{data q;} 
	: 
		q = QID:qualified_id{#QID=returnAST;} LPAREN v:(expression_list{#v=returnAST;})? RPAREN
		{#superclass_init = #(QID, (#[MY, "values"], v));}
	;

//dtor_head
dtor_head[int definition]
	:
		dtor_decl_spec
		dtor_declarator[definition]
	;

//dtor_decl_spec
dtor_decl_spec
	:
		(("inline"|"_inline"|"__inline")|"virtual")*
		{#dtor_decl_spec = #(#[MY, "specifier"], #dtor_decl_spec);}
	;

//dtor_declarator
dtor_declarator[int definition]
	{data s;}
	:	
		s = scope_override
		TILDE! ID
		{declaratorParameterList(definition);}
		LPAREN! ("void")? RPAREN!
		{declaratorEndParameterList(definition);}
		(exception_specification)?
	;

//dtor_body
dtor_body
	:
		compound_statement
		{endDestructorDefinition();}
	;

//parameter_list
parameter_list
	:	
		parameter_declaration_list (ELLIPSIS)?
		{#parameter_list = #(#[MYPARAM, "parameters"], #parameter_list);}
	;

//parameter_declaration_list
parameter_declaration_list
	:	
		(parameter_declaration (COMMA! parameter_declaration)* )
	;

parameter_initializer:
	remainder_expression	// DW 18/4/01 assignment_expression
	{#parameter_initializer = #(#[MY, "assign"], #parameter_initializer);}
	;
	
//parameter_declaration	(See also template_parameter_declaration)
parameter_declaration
	:	
		{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
			 (!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
			
			declaration_specifiers	// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> declarator        // if arg name given
			| 
				abstract_declarator     // if arg name not given  // can be empty
			)
		|
			(declarator)=> declarator			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL! 
		 parameter_initializer 
		)?
		{#parameter_declaration = #(#[MYDECLAR, "declaration"],#parameter_declaration);}
	;

//type_id
type_id!
	:
		s:declaration_specifiers{#s=returnAST;} a:abstract_declarator{#a=returnAST;}
		{
//		 #s->addChild(RefPNode(#a));
		 #type_id = #(#[MYTYPE, "typeid"],#s, #a);
		}
	;

/* This rule looks a bit weird because (...) can happen in two
 * places within the declaration such as "void (*)()" (ptr to
 * function returning nothing).  However, the () of a function
 * can only occur after having seen either a (abstract_declarator)
 * and not after a [..] or simple '*'.  These are the only two
 * valid () func-groups:
 *    int (*)();     // ptr to func
 *    int (*[])();   // array of ptr to func
 */
//abstract_declarator
abstract_declarator
	:	
		ptr_operator abstract_declarator 
	|	
		(LPAREN abstract_declarator RPAREN (LSQUARE|LPAREN) )=> LPAREN abstract_declarator RPAREN
		(options {warnWhenFollowAmbig = false;}:
		abstract_declarator_suffix)
	|	
		(options {warnWhenFollowAmbig = false;}:
		abstract_declarator_suffix)?
	;

//abstract_declarator_suffix
abstract_declarator_suffix
	:	
	!	(LSQUARE! c:(constant_expression{#c=returnAST;})? RSQUARE!)+
		{declaratorArray();}
		{#abstract_declarator_suffix = #(#[MY, "modifier"],#(#[MYDECLAR,"array"], c));}
	|
		LPAREN
		{declaratorParameterList(0);}
		(parameter_list)?
		RPAREN
		{declaratorEndParameterList(0);}
		cv_qualifier_seq
		(exception_specification)?
	;

//Fixed Wilson Chen, 16/7/2009, and the throw definition is not necessary anymore in C++
//exception_specification
exception_specification
	{ TypeSpecifier ts;
	}
	:	
		"throw"^ 
		LPAREN! 
		(	(ts=simple_type_specifier (ptr_operator)? (COMMA! ts=simple_type_specifier (ptr_operator)?)* )? 
		|	ELLIPSIS
		)
		RPAREN!
	;

//template_head
template_head
	:	
		"template"!
		LESSTHAN! template_parameter_list GREATERTHAN!
		{#template_head = #(#[MY, "templatedef"], #template_head);}
	;

//template_parameter_list
template_parameter_list
	:	
		{beginTemplateParameterList();}
		template_parameter (COMMA! template_parameter)*
		{endTemplateParameterList();}
		{#template_parameter_list = #(#[MY, "templatelist"], #template_parameter_list);}
	;

/* Rule requires >2 lookahead tokens. The ambiguity is resolved 
 * correctly, however. According to the manual "...A template argument
 * that can be interpreted either as a parameter-declaration or a
 * type-argument (because its identifier is the name of an
 * already existing class) is taken as type-argument."
 * Therefore, any "class ID" that is seen on the input, should
 * match the first alternative here (it should be a type-argument).
 */
//template_parameter
template_parameter
	:	
		(options{generateAmbigWarnings = false;}:
		 type_parameter
		|	
		 (parameter_declaration)=>
		  parameter_declaration
		|
		 template_parameter_declaration
		)
	;

//type_parameter
type_parameter!
	:
		(	
			("class"!|"typename"!) 
			(id:ID
				{
				templateTypeParameter((id->getText()).data());
				}
				as:(ASSIGNEQUAL! assigned_type_name{#as=#(#[MY,"assign"], returnAST);})?
			)?
			{#type_parameter = #(id, as, mod);}
		|
			mod:template_head{#mod=#(#[MY, "modifier"], returnAST);} "class" 
			(id2:ID
				{
				templateTypeParameter((id2->getText()).data());
				}
				(ASSIGNEQUAL! assigned_type_name{#as=#(#[MY,"assign"], returnAST);})?
			)?
			{#type_parameter = #(id2, as, mod);}
		)
	;

/* This is to allow an assigned type_name in a template parameter
 *	list to be defined previously in the same parameter list,
 *	as type setting is ineffective whilst guessing
 */
//assigned_type_name
assigned_type_name
	{data qt; TypeSpecifier ts;}
	:
		(options{generateAmbigWarnings = false;}:
			qt = qualified_type abstract_declarator	
		|
			ts = simple_type_specifier abstract_declarator
		)
	;

//template_parameter_declaration	(See also parameter_declaration)
template_parameter_declaration
	:	
		{beginParameterDeclaration();}
		(
			{!((LA(1)==SCOPE) && (LA(2)==STAR||LA(2)==OPERATOR)) &&
			 (!(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
			
			declaration_specifiers	// DW 24/3/98 Mods for K & R
			(  
				(declarator)=> declarator        // if arg name given
			| 
				abstract_declarator     // if arg name not given  // can be empty
			)
		|
			(declarator)=> declarator			// DW 24/3/98 Mods for K & R
		|
			ELLIPSIS
		)
		(ASSIGNEQUAL
		 additive_expression	// DW 04/09/07 because of ambiguity of ">"
		)?
	;

// This rule refers to an instance of a template class or function
//template_id
template_id	// aka template_class_name
	:	
		ID LESSTHAN template_argument_list GREATERTHAN
	;

//template_argument_list
template_argument_list
	:	
		template_argument (COMMA! template_argument)*
	;

/* Here assignment_expression was changed to shift_expression to rule out
 *  x< 1<2 > which causes ambiguities. As a result, these can be used only
 *  by enclosing parentheses x<(1<2)>. This is true for x<1+2> ==> bad,
 *  x<(1+2)> ==> ok.
 */
//template_argument
template_argument
	:
		// DW 07/04/05 This predicate only used here if next is SCOPE or ID
		{( !(LA(1)==SCOPE||LA(1)==ID) || qualifiedItemIsOneOf(qiType|qiCtor) )}?
		type_id
	|	
		shift_expression // failed in iosfwd
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  STATEMENTS ////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

//statement_list
statement_list
	:	
		(statement)+
	;

//statement
statement
	{
	lineNo = LT(1)->getLine();
	FunctionSpecifier fs = fsInvalid;	// inline,virtual,explicit
	}
	:
		(	("namespace"|"using")=>
			block_declaration
		|	(("typedef")? class_specifier (qualified_id)?)=>
			member_declaration
		|	(declaration_specifiers LPAREN ptr_operator qualified_id RPAREN)=>
			member_declaration
		|	(declaration_specifiers (ptr_operator ptr_operator) qualified_id)=>
			member_declaration
		|	(declaration_specifiers ((ptr_operator)=>ptr_operator)? qualified_id)=>
			member_declaration
		|	labeled_statement
		|	case_statement
		|	default_statement
		|	expression SEMICOLON! {end_of_stmt();}
			{if(#statement != nullAST) #statement = #(#[MYEXPRESSION, "expression"], #statement);}
		|	compound_statement
		|	selection_statement
		|	iteration_statement
		|	jump_statement
		|	SEMICOLON! {end_of_stmt();}
		|	try_block
		|	ep_try_block
		|	throw_statement
			// The next two entries may be used for debugging
			// Use this statement in the source code to turn antlr trace on (See note above)
		|	"antlrTrace_on" {antlrTrace(true);}
			// Use this statement in the source code to turn antlr trace off (See note above)
		|	"antlrTrace_off" {antlrTrace(false);}
		)
	;

//block_declaration
block_declaration
	:	simple_declaration
	|	namespace_alias_definition
	|	using_statement
	;

//simple_declaration
simple_declaration
	:
		declaration_specifiers (init_declarator_list)? SEMICOLON! {end_of_stmt();}
	;

//labeled_statement
labeled_statement!
	:	
		id:ID COLON s:statement
		{#labeled_statement = #(#[MY, "label"], id);
		 #labeled_statement->setNextSibling(ANTLR_USE_NAMESPACE(antlr)RefAST(#s));
		}
	;

//case_statement
case_statement!
	:	"case"
		ce:constant_expression COLON s:statement
		{#case_statement = #(#[MY, "case"], #(#[MYEXPRESSION,"value"],#ce), #(#[MYEXPRESSION,"body"], #s));}
	;

//default_statement
default_statement!
	:	
		"default" COLON s:statement
		{#default_statement = #(#[MY, "default"], #(#[MYEXPRESSION,"body"], #s));}
	;

//compound_statement
compound_statement
	:	
		LCURLY! 
		{end_of_stmt();
		 enterNewLocalScope();
		}
		(statement_list)?
		RCURLY! 
		{exitLocalScope();}
		{#compound_statement = #(#[MYBODY, "body"], #compound_statement);}
	;

/* NOTE: cannot remove ELSE ambiguity, but it parses correctly.
 * The warning is removed with the options statement
 */
//selection_statement
selection_statement
	:	
	!	"if" LPAREN 
		{enterNewLocalScope();}
		condition:condition RPAREN
		left:statement
		(options {warnWhenFollowAmbig = false;}:
		 "else" right:statement)?
		{exitLocalScope();}
		{#selection_statement = #(#[MYSTATEMENT, "if"], condition, #(#[MYEXPRESSION, "left"], left), #(#[MYEXPRESSION, "right"], right));}
	|	
		"switch"^ LPAREN!
		{enterNewLocalScope();}
		condition RPAREN! statement
		{exitLocalScope();}
	;

//iteration_statement
iteration_statement!
	:	
		"while"	LPAREN
		{enterNewLocalScope();}
		c0:condition RPAREN 
		s0:statement  
		{exitLocalScope();}
		{#iteration_statement = #(#[MYSTATEMENT, "while"], c0, #(#[MY, "body"], s0));}
	|	
		"do"
		{enterNewLocalScope();}
		s1:statement "while"
		LPAREN e0:expression RPAREN
		{exitLocalScope();}
		SEMICOLON {end_of_stmt();} 
		{#iteration_statement = #(#[MYSTATEMENT, "do"], #(#[MY, "body"], s1), #(#[MY, "while"], e0));}
	|	
		"for" LPAREN
		{enterNewLocalScope();}
		(	(declaration)=> d:declaration 
		|	(e1:expression)? SEMICOLON {end_of_stmt();}
		)
		(c:condition)? SEMICOLON {end_of_stmt();}
		(e2:expression)?
		RPAREN s:statement	 
		{exitLocalScope();}
		{#iteration_statement = #(#[MYSTATEMENT, "for"], #(#[MY, "init"], d, e1), c, #(#[MY, "iterator"], e2), #(#[MY, "body"], s));}
	;

//condition
condition
	:
		(	(declaration_specifiers declarator ASSIGNEQUAL)=> 
			 declaration_specifiers declarator ASSIGNEQUAL remainder_expression
		|	expression
		{#condition = #(#[MY, "condition"], #condition);}
		)
	;

//jump_statement
jump_statement
	:	
		(	"goto"^ ID SEMICOLON! {end_of_stmt();}
		|	"continue" SEMICOLON! {end_of_stmt();}
		|	"break" SEMICOLON! {end_of_stmt();}
		|	// DW 16/05/03 May be problem here if return is followed by a cast expression 
			"return"^ {in_return = true;}
			(	options{warnWhenFollowAmbig = false;}:
				(LPAREN {(qualifiedItemIsOneOf(qiType) )}? ID RPAREN)=> 
				LPAREN! ID RPAREN! (expression)?	// This is an unsatisfactory fix for problem in xstring re "return (allocator);"
												//  and in xlocale re return (_E)(_Tolower((unsigned char)_C, &_Ctype));
												//	still can't go to here!
				//{OUTPUT_DEBUG("%d CPP_parser.g jump_statement Return fix used\n",lineNo);}
			|	expression 
			)?	SEMICOLON! {in_return = false,end_of_stmt();} 
		)
	;

//Add to support MSVC SEH exception. Wilson Chen, 16/7/2009
//ep_try_block
ep_try_block
	:
		"__try"^ compound_statement (ep_exception)? (ep_finally)?
	;

//ep_exception
ep_exception!
	:	
		"__except" LPAREN e:expression RPAREN s:compound_statement
		{#ep_exception = #(#[MY, "__except"], #(#[MY, "condition"], e), s);}
	;
	
//ep_finally
ep_finally
	:
		"__finally"^ compound_statement
	;
	
//try_block
try_block
	:	
		"try"^ compound_statement (handler)*
	;

//handler
handler
	:	
		"catch"^
		{exceptionBeginHandler();}
		{declaratorParameterList(1);}
		LPAREN! exception_declaration RPAREN!
		{declaratorEndParameterList(1);}
		compound_statement
		{exceptionEndHandler();}
	;

//exception_declaration
exception_declaration
	:	
		parameter_declaration_list
		{#exception_declaration = #(#[MY, "exceptions"], #exception_declaration);}
	;

/* This is an expression of type void according to the ARM, which
 * to me means "statement"; it removes some ambiguity to put it in
 * as a statement also.
 */
//throw_statement
throw_statement
	:	
		"throw"^ (assignment_expression)? SEMICOLON! { end_of_stmt();}
	;

//using_statement
using_statement
	{data qid;}
	:		
		"using"^
		("namespace" qid = qualified_id		// Using-directive
		|("typename")? qid = qualified_id	// Using-declaration
		)
		SEMICOLON! {end_of_stmt();}
	;

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////////  EXPRESSIONS ///////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////

// Same as expression_list
//expression
expression
	{
	lineNo = LT(1)->getLine();
	}
	:	
		assignment_expression (COMMA! assignment_expression)*
	;

// right-to-left for assignment op
//assignment_expression
assignment_expression
	:	
		conditional_expression
		(	
			(ASSIGNEQUAL^|TIMESEQUAL^|DIVIDEEQUAL^|MINUSEQUAL^|PLUSEQUAL^
			|MODEQUAL^|SHIFTLEFTEQUAL^|SHIFTRIGHTEQUAL^|BITWISEANDEQUAL^
			|BITWISEXOREQUAL^|BITWISEOREQUAL^
			)
			remainder_expression
		)?
	;

//remainder_expression
remainder_expression
	:
		(	
			(conditional_expression (COMMA|SEMICOLON|RPAREN) )=>
			{assign_stmt_RHS_found += 1;}
			assignment_expression
			{
			if (assign_stmt_RHS_found > 0)
				assign_stmt_RHS_found -= 1;
			else
				{
				fprintf(stderr,"%d warning Error in assign_stmt_RHS_found = %d\n",
					lineNo,assign_stmt_RHS_found);
				fprintf(stderr,"Press return to continue\n");
				getchar();
				}
			}
		|	
			assignment_expression
		)
	;

//conditional_expression
conditional_expression!
	{
		bool bQuestion = false;
	}
	:	
		l:logical_or_expression
		(QUESTIONMARK e:expression COLON v:conditional_expression {bQuestion = true;})?
		{
			if(bQuestion==true)
				#conditional_expression = #(#[MYSTATEMENT, "ifexp"], #(#[MY, "condition"],l), #(#[MY, "left"], e), #(#[MY, "right"], v));
			else
				#conditional_expression = #l;
		}
	;

//constant_expression
constant_expression
	:	
		conditional_expression
	;

//logical_or_expression
logical_or_expression
	:	
		logical_and_expression (OR^ logical_and_expression)* 
	;

//logical_and_expression
logical_and_expression
	:	
		inclusive_or_expression (AND^ inclusive_or_expression)* 
	;

//inclusive_or_expression
inclusive_or_expression
	:	
		exclusive_or_expression (BITWISEOR^ exclusive_or_expression)*
	;

//exclusive_or_expression
exclusive_or_expression
	:	
		and_expression (BITWISEXOR^ and_expression)*
	;

//and_expression
and_expression
	:	
		equality_expression (AMPERSAND^ equality_expression)*
	;

//equality_expression
equality_expression
	:	
		relational_expression ( (NOTEQUAL^|EQUAL^) relational_expression)*
	;

//relational_expression
relational_expression
	:	
		shift_expression
		(options {warnWhenFollowAmbig = false;}:
			(	LESSTHAN^
			|	GREATERTHAN^
			|	LESSTHANOREQUALTO^
			|	GREATERTHANOREQUALTO^
			)
		 shift_expression
		)*
	;

//shift_expression
shift_expression
	:	
		additive_expression ((SHIFTLEFT^ | SHIFTRIGHT^) additive_expression)*
	;

// See comment for multiplicative_expression regarding #pragma
additive_expression
	:	
		multiplicative_expression
		(options{warnWhenFollowAmbig = false;}:
			(PLUS^ | MINUS^) multiplicative_expression
		)*
	;

// ANTLR has trouble dealing with the analysis of the confusing unary/binary
// operators such as STAR, AMPERSAND, PLUS, etc...  
// With the #pragma (now "(options{warnWhenFollowAmbig = false;}:" etc.)
// we simply tell ANTLR to use the "quick-to-analyze" approximate lookahead
// as full LL(k) lookahead will not resolve the ambiguity anyway.  Might
// as well not bother.  This has the side-benefit that ANTLR doesn't go
// off to lunch here (take infinite time to read grammar).
multiplicative_expression
	:	
		pm_expression
		(options{warnWhenFollowAmbig = false;}:
			(STAR^|DIVIDE^|MOD^) pm_expression
		)*
	;

//pm_expression
pm_expression
	:	
		cast_expression ( (DOTMBR^|POINTERTOMBR^) cast_expression)*
	;

/* The string "( ID" can be either the start of a cast or
 * the start of a unary_expression.  However, the ID must
 * be a type name for it to be a cast.  Since ANTLR can only hoist
 * semantic predicates that are visible without consuming a token,
 * the semantic predicate in rule type_name is not hoisted--hence, the
 * rule is reported to be ambiguous.  I am manually putting in the
 * correctly hoisted predicate.
 *
 * Ack! Actually "( ID" might be the start of "(T(expr))" which makes
 * the first parens just an ordinary expression grouping.  The solution
 * is to look at what follows the type, T.  Note, this could be a
 * qualified type.  Yucko.  I believe that "(T(" can only imply
 * function-style type cast in an expression (...) grouping.
 *
 * We DO NOT handle the following situation correctly at the moment:
 * Suppose you have
 *    struct rusage rusage;
 *    return (rusage.fp);
 *    return (rusage*)p;
 * Now essentially there is an ambiguity here. If rusage is followed by any
 * postix operators then it is an identifier else it is a type name. This
 * problem does not occur in C because, unless the tag struct is attached,
 * rusage is not a type name. However in C++ that restriction is removed.
 * No *real* programmer would do this, but it's in the C++ standard just for
 * fun..
 *
 * Another fun one (from an LL standpoint):
 *
 *   (A::B::T *)v;      // that's a cast of v to type A::B::T
 *   (A::B::foo);    // that's a simple member access
 *
 * The qualifiedItemIs(1) function scans ahead to what follows the
 * final "::" and returns qiType if the item is a type.  The offset of
 * '1' makes it ignore the initial LPAREN; normally, the offset is 0.
 */
//cast_expression
cast_expression 
	:
		(LPAREN type_id RPAREN unary_expression)=>
		 LPAREN! type_id RPAREN! unary_expression
		{#cast_expression = #(#[MY, "cast"], #cast_expression);}	
	|
		// Believe it or not, you can get more than one cast expression in sequence
		(LPAREN type_id RPAREN cast_expression)=>
		 LPAREN! type_id RPAREN! cast_expression
		{#cast_expression = #(#[MY, "cast"], #cast_expression);}	
	|  
		unary_expression	// handles outer (...) of "(T(expr))"
	
	;

//unary_expression
unary_expression
	:
		(	
			(postfix_expression)=> 
			postfix_expression
		|	
			PLUSPLUS^ unary_expression
		|	
			MINUSMINUS^ unary_expression
		|!	
			uo:unary_operator ce:cast_expression
			{#unary_expression = #(#uo, #ce);}
		|	
			("sizeof"^
			|"__alignof__"^ 	//Zhaojz 02/02/05 to fix bug 29 (GNU)
			)
			(	(unary_expression)=>
				 unary_expression
			|
				LPAREN! type_id RPAREN!
			)
		|   
			(SCOPE)?
			(new_expression
			|delete_expression
			)
		)
	;

//postfix_expression
postfix_expression [RefPNode recur = RefPNode(nullAST)]
	{
	 TypeSpecifier ts;
	 bool bDot;
	}
	:
	(	
		options {warnWhenFollowAmbig = false;}:
		// Function-style cast must have a leading type
		{!(LA(1)==LPAREN)}?
		(ts = simple_type_specifier LPAREN RPAREN LPAREN)=>	// DW 01/08/03 To cope with problem in xtree (see test10.i)
		 ts = simple_type_specifier LPAREN RPAREN LPAREN (expression_list)? RPAREN
	|!
		{!(LA(1)==LPAREN)}?
		(ts = simple_type_specifier LPAREN)=>
		 ts = tss:simple_type_specifier LPAREN (tel:expression_list)? RPAREN
		{
		 #tss = #(#tdot, #(#[MYCALL, "call"], #(#[MY,"convertor"], #tss), #(#[MY, "parameters"], #tel)));
		 #ps = #tss;
		}
		// Following put in to allow for the above being a constructor as shown in test_constructors_destructors.cpp
		// Fix, maybe a pointer converter then call its function; and code to let it recursive, it is now hard to read. 14/7/2009
		(bDot=tdot:dot_expression 
			{
			if(bDot==true)
				#tss = #(#tdot, #(#[MYCALL, "call"], #(#[MY,"ctor"], #tss), #(#[MY, "parameters"], #tel)));
			}
		ps:postfix_expression[#tss])?
		{#postfix_expression=#ps;}
	|!  
		p:primary_expression {if(recur != nullAST) #p->addChild(recur);}
		(options {warnWhenFollowAmbig = false;}:
        	array:(LSQUARE expression RSQUARE) 
        	{
        	 if(#array == nullAST)
        		#array = #[MY, "array"];
        	 #array->addChild(returnAST);
        	}
		|	
			LPAREN (el:expression_list)? RPAREN 
			{#p = #(#[MYCALL, "call"], #(#[MY, "function"],#p), #(#[MY, "parameters"], #el));}
		|	bDot=ob:dot_expression (t:"template")? id:id_expression
			{ #p = #(id, #(ob, p), t);	}
		|	PLUSPLUS {#p->addChild(RefPNode(#[MY, "++"]));}
		|	MINUSMINUS {#p->addChild(RefPNode(#[MY, "--"]));}
		)*
		{ 
		 if(#array != nullAST)
			#p->addChild(#array);
		 #postfix_expression = #p;
		}
	|
		("dynamic_cast"^|"static_cast"^|"reinterpret_cast"^|"const_cast"^)
		ts = cast_type
		LPAREN! expression RPAREN!
//	|
//		"typeid" 
//		LPAREN ((type_id)=>type_id|expression) RPAREN
//		(dot_expression postfix_expression)?					//treat typeid as a function call, add it into qualified_id, 
	)
	;

//cast_type
cast_type returns [CPPParser::TypeSpecifier ts]
	:
	LESSTHAN! ("const")? ts = type_specifier (ptr_operator)? GREATERTHAN!
	{#cast_type=#(#[MY, "casttype"], #cast_type);}
	;
	
//dot_expression
dot_expression returns [bool bDot = false]
	:
	(DOT{bDot=true;}|POINTERTO{bDot=false;})
	;
	
//primary_expression
primary_expression
	:	id_expression
	|	literal
	|	"this"
	|	LPAREN! expression RPAREN!
	;

//id_expression
id_expression 
	{
	data s;
	}
	:
		(	s = qualified_id 
		)
	;

//literal
literal
	:	OCTALINT
	|	DECIMALINT
	|	HEXADECIMALINT
	|	CharLiteral
	|	WCharLiteral
	|	(StringLiteral|WStringLiteral)+
	|	FLOATONE
	|	FLOATTWO
	|	"true"
	|	"false"
	;

//unary_operator
unary_operator
	:	AMPERSAND
	|	STAR
	|	PLUS
	|	MINUS
	|	TILDE
	|	NOT
	;

/* JEL The first ()? is used to resolve "new (expr) (type)" because both
 * (expr) and (type) look identical until you've seen the whole thing.
 *
 * new_initializer appears to be conflicting with function arguments as
 * function arguments can follow a primary_expression.  [This is a full
 * LL(k) versus LALL(k) problem.  Enhancing context by duplication of
 * some rules might handle this.]
 */
//new_expression
new_expression
	:
	(  
		"new"^
		(	(LPAREN expression_list RPAREN)=> 
			 LPAREN expression_list RPAREN)?
		(new_type_id|LPAREN type_id RPAREN)
		(options{warnWhenFollowAmbig = false;}:	
		(new_initializer)=> new_initializer)?
	)
	;

//new_initializer
new_initializer
	:	
		LPAREN! (expression_list)? RPAREN!
		{#new_initializer = #(#[MY, "parameters"], #new_initializer);}
	;

//new_type_id
new_type_id
	:	
		declaration_specifiers 
		(options {warnWhenFollowAmbig = false;}:
			new_declarator 
		)?
	;

//new_declarator
new_declarator
	:	 
		ptr_operator
		(options {warnWhenFollowAmbig = false;}:
		new_declarator)?
	|	
		direct_new_declarator
	;

/* The "[expression]" construct conflicts with the "new []" construct
 * (and possibly others).  We used approximate lookahead for the "new []"
 * construct so that it would not try to compute full LL(2) lookahead.
 * Here, we use #pragma approx again because anytime we see a [ followed
 * by token that can begin an expression, we always want to loop.
 * Approximate lookahead handles this correctly.  In fact, approximate
 * lookahead is the same as full lookahead when all but the last lookahead
 * depth are singleton sets; e.g., {"["} followed by FIRST(expression).
 */
//direct_new_declarator
direct_new_declarator
	:
		(options {warnWhenFollowAmbig = false;}:
			LSQUARE! expression RSQUARE!
		)+
	{#direct_new_declarator = #(#[MY, "array"], #direct_new_declarator);}
	;

//ptr_operator
ptr_operator
	{data s;}
	:	
		(	AMPERSAND 	{is_address = true;}
		|	("_cdecl"|"__cdecl") 
		|	("_near"|"__near") 
		|	("_far"|"__far") 
		|	"__interrupt" 
		|	("pascal"|"_pascal"|"__pascal") 
		|	("_stdcall"|"__stdcall") 
		|	(s = scope_override STAR cv_qualifier_seq)=>
			 s = scope_override STAR {is_pointer = true;} cv_qualifier_seq
		)	
	{#ptr_operator=#(#[MY, "modifier"], #ptr_operator);}
   ;

// Match A::B::*	// May be redundant 14/06/06
//ptr_to_member
ptr_to_member	// Part of ptr_operator in grammar.txt
	{data s;}
	:
		s = scope_override STAR  {is_pointer = true;} cv_qualifier_seq
	;

// JEL note:  does not use (const|volatile)* to avoid lookahead problems
//cv_qualifier_seq
cv_qualifier_seq
	{CPPParser::TypeQualifier tq;}
	:
		(tq = type_qualifier)*
	;

// Match "(::)A::B::C::(template)" or just "::"
//scope_override
scope_override! returns [data so]
	{
	char sitem[CPPParser_MaxQualifiedItemSize+1];
	// The above statement must be non static because its calling is nested
	sitem[0] = '\0';
	}
	:
		(SCOPE {strcat(sitem,"::");} )?
		(	options {warnWhenFollowAmbig = false;}:
			(ID LESSTHAN template_argument_list GREATERTHAN SCOPE)=>
			id1:ID {strcat(sitem,(id1->getText()).data());}
			LESSTHAN template_argument_list GREATERTHAN {#id1=#(id1, (#[MY, "templatelist"], returnAST));}// {strcat(sitem,"<...>");}
			SCOPE{strcat(sitem,"::");}
			(tp1:"template" {strcat(sitem,"template");#id1->getFirstChild()->setNextSibling(ANTLR_USE_NAMESPACE(antlr)RefAST(#tp1));})?
			{
			 if(#scope_override == nullAST)	#scope_override=#[MY, "scope"];
			 #scope_override->addChild(#id1);
			}
		|	
			id2:ID {strcat(sitem,(id2->getText()).data());}
			SCOPE {strcat(sitem,"::");}
			(tp2:"template" {strcat(sitem,"template");#id2->addChild(#tp2);})?
			{
			 if(#scope_override == nullAST)	#scope_override=#[MY, "scope"];
			 #scope_override->addChild(#id2);
			}
		)*
		{
		 so = sitem;
		}
	;

//delete_expression
delete_expression
	:	
		"delete"^ (LSQUARE! RSQUARE!{astFactory->addASTChild(currentAST, #[MY, "array"]);})? cast_expression
	;

// Same as expression
//expression_list
expression_list
	:	
		assignment_expression (COMMA! assignment_expression)*
	;

//optor
optor returns [data s]
	{
	char sitem[CPPParser_MaxQualifiedItemSize+1];
	sitem[0]='\0';
	TypeSpecifier ts=tsInvalid;
	char *opitem;
	}
	:	
		(	"new" {strcat(sitem," new");}
			(options {warnWhenFollowAmbig = false;}:
				LSQUARE RSQUARE  {strcat(sitem,"[]");} )?
		|   
			"delete" {strcat(sitem," delete");}
			(options {warnWhenFollowAmbig = false;}:
				LSQUARE RSQUARE  {strcat(sitem,"[]");} )?
		|	
			LPAREN RPAREN!  {strcat(sitem,"()");}
		|	
			LSQUARE RSQUARE!  {strcat(sitem,"[]");}
		|
			{strcat(sitem,(LT(1)->getText()).data());}
			optor_simple_tokclass
		|
			{strcat(sitem,"type-specifier()");}
			ts = type_specifier LPAREN RPAREN!
		)
		{
		s = sitem;
		#optor = #(#[MYFUNCTION, "operator"], #optor);
		}
	;

// optor_simple_tokclass
optor_simple_tokclass
	:
    (PLUS|MINUS|STAR|DIVIDE|MOD|BITWISEXOR|AMPERSAND|BITWISEOR|TILDE|NOT|
	 SHIFTLEFT|SHIFTRIGHT|
	 ASSIGNEQUAL|TIMESEQUAL|DIVIDEEQUAL|MODEQUAL|PLUSEQUAL|MINUSEQUAL|
	 SHIFTLEFTEQUAL|SHIFTRIGHTEQUAL|BITWISEANDEQUAL|BITWISEXOREQUAL|BITWISEOREQUAL|
	 EQUAL|NOTEQUAL|LESSTHAN|GREATERTHAN|LESSTHANOREQUALTO|GREATERTHANOREQUALTO|OR|AND|
	 PLUSPLUS|MINUSMINUS|COMMA|POINTERTO|POINTERTOMBR
	)
	;

{
// Possibility of global stuff in the lexer cpp file

bool in_user_file_deferred = false;	// used to record first detection of user file

int deferredLineCount = 0;	// Used to accumulate line numbers in comments etc.

char principal_file[128];	// Path and name of user file set on reading the first preprocessor #line directive
int principal_line = 0;		// principal file's line number
int principal_last_set = 0; // where principal file's line number was last set

char current_included_file[128];	// Path and name of current include file
int include_line = 0; // include file's line number
int include_last_set = 0; // where included file's line number was last set

}

class CPPLexer extends Lexer;

options
	{
	k = 3;
	exportVocab = STDC;
	testLiterals = true;
	}

// DW 4/11/02 put in to support manual hoisting
tokens
	{
	OPERATOR = "operator";
	MY;
	MYFUNCTION<AST=CFunctionNode>;
	MYPARAM;
	MYDECLAR<AST=CDeclarationNode>;
	MYEXPRESSION<AST=CExpressionNode>;
	MYBODY;
	MYSTATEMENT;
	MYCLASS<AST=CClassNode>;
	MYTEMPLATE<AST=CTemplateNode>;
	MYNAMESPACE<AST=CNamespaceNode>;
	MYTYPEDEF<AST=CTypedefNode>;
	MYENUM;
	MYTYPE<AST=CTypeNode>;
	MYCALL;
	MYNEW;
	}

{
void deferredNewline() 
	{
	deferredLineCount++;	// Declared and initialised in main.cpp (Not true!)
	}

void newline() 
	{
	for (;deferredLineCount>0;deferredLineCount--)
	    {
		CharScanner::newline();
		}
    CharScanner::newline();
    }

// for processing #line .... lines (see note above)
void process_line_directive(const char *includedFile, const char *includedLineNo)
	{
	// See global interface variables above
	// Working variables
	static int line, result;
	static bool principal_file_set = false;
	static int x;
	// Extract included file line no.
	result = sscanf(includedLineNo, "%d \n", &line);

	//OUTPUT_DEBUG("CPPLexer line directive on line %d\n",lineNo);
	// remove first " from file path+name by shifting all characters left
	for(x=1;includedFile[x]!='"';x++)
		{
		current_included_file[x-1] = includedFile[x];
		}

	// Check path and name are not too long
	if(x>128)
		{
		//
		OUTPUT_DEBUG("Path and name of included file too long\n");
		OUTPUT_DEBUG("Increase length of current_included_file and\n");
		OUTPUT_DEBUG("  principal_file to at least %d characters\n",x);
		OUTPUT_DEBUG("Abandon run\n");
		getchar();		    
		}

	// Replace last " from file name with null
	current_included_file[x-1] = NULL;

	// This will occur on reading the first preprocessor #line directive
	if (!principal_file_set)
		{
		strcpy (principal_file, current_included_file);
		principal_file_set = true;
		}

	// check for main file name
	if (strcmp(principal_file, current_included_file) == 0)
		{
		principal_line = line;	// this is line no. shown in line directive
		principal_last_set = CharScanner::getLine();	// This is line no. in preprocessed *.i file
		strcpy(current_included_file, " "); // delete include file name
		in_user_file_deferred = true; // Users's .C or .CPP file (aka principal_file) detected
		}
	else
		// Check that this is a genuine path
		if(current_included_file[1]==':')
			{//OUTPUT_DEBUG("main.cpp 222 entered\n");
			//OUTPUT_DEBUG("main.cpp 223 %s %s\n",principal_file,current_included_file);
			include_line = line;	// this is line no. shown in line directive
			include_last_set = CharScanner::getLine();	// This is line no. in preprocessed *.i file
			in_user_file_deferred = false; // Header file file detected
			}
	}

}

// Operators:

ASSIGNEQUAL     : '=' ;
COLON           : ':' ;
COMMA           : ',' ;
QUESTIONMARK    : '?' ;
SEMICOLON       : ';' ;
POINTERTO       : "->" ;

// DOT & ELLIPSIS are commented out since they are generated as part of
// the Number rule below due to some bizarre lexical ambiguity shme.
// DOT  :       '.' ;
// ELLIPSIS      : "..." ;

LPAREN          : '(' ;
RPAREN          : ')' ;
LSQUARE         : '[' ;
RSQUARE         : ']' ;
LCURLY          : '{' ;
RCURLY          : '}' ;

EQUAL           : "==" ;
NOTEQUAL        : "!=" ;
LESSTHANOREQUALTO     : "<=" ;
LESSTHAN              : "<" ;
GREATERTHANOREQUALTO  : ">=" ;
GREATERTHAN           : ">" ;

DIVIDE          : '/' ;
DIVIDEEQUAL     : "/=" ;
PLUS            : '+' ;
PLUSEQUAL       : "+=" ;
PLUSPLUS        : "++" ;
MINUS           : '-' ;
MINUSEQUAL      : "-=" ;
MINUSMINUS      : "--" ;
STAR            : '*' ;
TIMESEQUAL      : "*=" ;
MOD             : '%' ;
MODEQUAL        : "%=" ;
SHIFTRIGHT      : ">>" ;
SHIFTRIGHTEQUAL : ">>=" ;
SHIFTLEFT       : "<<" ;
SHIFTLEFTEQUAL  : "<<=" ;

AND            : "&&" ;
NOT            : '!' ;
OR             : "||" ;

AMPERSAND       : '&' ;
BITWISEANDEQUAL : "&=" ;
TILDE           : '~' ;
//BITWISEAND      : " & " ;
BITWISEOR       : '|' ;
BITWISEOREQUAL  : "|=" ;
BITWISEXOR      : '^' ;
BITWISEXOREQUAL : "^=" ;

//Zuo: the following tokens are come from cplusplus.g

POINTERTOMBR    : "->*" ;
DOTMBR          : ".*"  ;

SCOPE           : "::"  ;

Whitespace	
	:	
		(	// Ignore space
			Space
		|	// handle newlines
			(	'\r' '\n'	// MS
			|	'\r'		// Mac
			|	'\n'		// Unix 
			)	{newline();}
		|	// handle continuation lines
			(	'\\' '\r' '\n'	// MS
			|	'\\' '\r'		// Mac
			|	'\\' '\n'		// Unix 
			)	{OUTPUT_DEBUG("CPP_parser.g continuation line detected on line %d\n",lineNo);
				deferredNewline();}
		)	
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
	;

Comment  
	:	
		"/*"   
		(	{LA(2) != '/'}? '*'
		|	EndOfLine {deferredNewline();}
		|	~('*'| '\r' | '\n')
		)*
		"*/" {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
	;

CPPComment
	:	
		"//" (~('\n' | '\r'))* EndOfLine
 		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}                     
	;

PREPROC_DIRECTIVE
	options{paraphrase = "a line directive";}
	:	
		'#' LineDirective
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();} 
	;

protected 
LineDirective
	:
		("line")?  // this would be for if the directive started "#line"
		(Space)+
		n:Decimal
		(Space)+
		(sl:StringLiteral)
		((Space)+ Decimal)*	// To support cpp flags (GNU)
		{
		process_line_directive((sl->getText()).data(), (n->getText()).data());  // see main()
		}
		EndOfLine
	;

protected  
Space
	:	
			(' '|'\t' {tab();}|'\f')
	;

Pragma
	:	
		('#' "pragma"	(	(EndOfContinuedLine)=>EndOfContinuedLine
						|	~('\r' | '\n')
						)* EndOfLine
		)
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}
	;

Error
	:	
		('#' "error"	(	(EndOfContinuedLine)=>EndOfContinuedLine
						|	~('\r' | '\n')
						)* EndOfLine
		)
		{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP; newline();}
	;

// Literals:

/*
 * Note that we do NOT handle tri-graphs nor multi-byte sequences.
 */

/*
 * Note that we can't have empty character constants (even though we
 * can have empty strings :-).
 */
CharLiteral
	:	
		'\'' ( Escape | UniversalCharacterName | ~('\''|'\\'|'\n'|'\r') ) '\''
	;

WCharLiteral
	:
		'L' CharLiteral
	;

/*
 * Can't have raw imbedded newlines in string constants.  Strict reading of
 * the standard gives odd dichotomy between newlines & carriage returns.
 * Go figure.
 */
StringLiteral
	:	
		'"'
		(	Escape
		|	UniversalCharacterName
		|	~('"'|'\\'|'\n'|'\r')
		)*
		'"'
	;

WStringLiteral
	:
		'L' StringLiteral
	;

protected
EndOfContinuedLine
	:
		(options{generateAmbigWarnings = false;}:
			'\\' '\r' '\n'	// MS
		|	'\\' '\r'		// Mac
		|	'\\' '\n'		// Unix 
		)	{deferredNewline();}
	;

protected
EndOfLine
	:	
		(options{generateAmbigWarnings = false;}:
			"\r\n"  // MS
		|	'\r'    // Mac
		|	'\n'    // Unix
		)
	;

/*
 * Handle the various escape sequences.
 *
 * Note carefully that these numeric escape *sequences* are *not* of the
 * same form as the C language numeric *constants*.
 *
 * There is no such thing as a binary numeric escape sequence.
 *
 * Octal escape sequences are either 1, 2, or 3 octal digits exactly.
 *
 * There is no such thing as a decimal escape sequence.
 *
 * Hexadecimal escape sequences are begun with a leading \x and continue
 * until a non-hexadecimal character is found.
 *
 * No real handling of tri-graph sequences, yet.
 */

protected
Escape  
	:	
		'\\'
		( options{warnWhenFollowAmbig=false;}:
		  'a'
		| 'b'
		| 'f'
		| 'n'
		| 'r'
		| 't'
		| 'v'
		| '"'
		| '\''
		| '\\'
		| '?'
		| ('0'..'3') (options{warnWhenFollowAmbig=false;}: Digit (options{warnWhenFollowAmbig=false;}: Digit)? )?
		| ('4'..'7') (options{warnWhenFollowAmbig=false;}: Digit)?
		| 'x' (options{warnWhenFollowAmbig=false;}: HexadecimalDigit)+ //Digit | 'a'..'f' | 'A'..'F')+
		)
	;

// Numeric Constants: 


protected
Digit
	:	
		'0'..'9'
	;

protected
Decimal
	:	
		('0'..'9')+
	;

protected
LongSuffix
	:	'l'
	|	'L'
	;

protected
UnsignedSuffix
	:	'u'
	|	'U'
	;

protected
FloatSuffix
	:	'f'
	|	'F'
	;

protected
Exponent
	:	
		('e'|'E') ('+'|'-')? (Digit)+
	;

protected
UniversalCharacterName
	:
		"\\u" HexQuad
	|	"\\U" HexQuad HexQuad
	;

protected
HexQuad
	:
		HexadecimalDigit HexadecimalDigit HexadecimalDigit HexadecimalDigit 
	;

protected
HexadecimalDigit
	:
		('0'..'9'|'a'..'f'|'A'..'F')
	;

protected
Vocabulary
	:	
		'\3'..'\377'
	;

Number
	:	
		( (Digit)+ ('.' | 'e' | 'E') )=> 
		(Digit)+
		( '.' (Digit)* (Exponent)? {_ttype = FLOATONE;} //Zuo 3/12/01
		| Exponent                 {_ttype = FLOATTWO;} //Zuo 3/12/01
		)                          //{_ttype = DoubleDoubleConst;}
		(FloatSuffix               //{_ttype = FloatDoubleConst;}
		|LongSuffix                //{_ttype = LongDoubleConst;}
		)?
	|	
		("...")=> "..."            {_ttype = ELLIPSIS;}
	|	
		'.'                        {_ttype = DOT;}
		(	(Digit)+ (Exponent)?   {_ttype = FLOATONE;} //Zuo 3/12/01
                                   //{_ttype = DoubleDoubleConst;}
			(FloatSuffix           //{_ttype = FloatDoubleConst;}
			|LongSuffix            //{_ttype = LongDoubleConst;}
			)?
		)?
	|	
		'0' ('0'..'7')*            //{_ttype = IntOctalConst;}
		(LongSuffix                //{_ttype = LongOctalConst;}
		|UnsignedSuffix            //{_ttype = UnsignedOctalConst;}
		)*                         {_ttype = OCTALINT;}
	|	
		'1'..'9' (Digit)*          //{_ttype = IntIntConst;}
		(LongSuffix                //{_ttype = LongIntConst;}
		|UnsignedSuffix            //{_ttype = UnsignedIntConst;}
		)*                         {_ttype = DECIMALINT;}  
	|	
		'0' ('x' | 'X') (HexadecimalDigit)+ //('a'..'f' | 'A'..'F' | Digit)+
                                   //{_ttype = IntHexConst;}
		(LongSuffix                //{_ttype = LongHexConst;}
		|UnsignedSuffix            //{_ttype = UnsignedHexConst;}
		)*                         {_ttype = HEXADECIMALINT;}   
	;

ID
	options {testLiterals = true;}
	:	
		(("asm"|"_asm"|"__asm") Whitespace )=>

		("asm"|"_asm"|"__asm") 
			(EndOfLine {deferredNewline();}
			|Space
			)+
		(
			LPAREN
				(	EndOfLine {deferredNewline();}	
				|	~(')' | '\r' | '\n')
				)*	
			RPAREN {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
		|
			LCURLY
				(	EndOfLine {deferredNewline();}	
				|	~('}' | '\r' | '\n')
				)*	
			RCURLY {_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
		|
			// Single line asm statement
			(~('(' | ')' | '{' | '}' | '\n' | '\r' | ' ' | '\t' | '\f'))
			(~('(' | ')' | '{' | '}' | '\n' | '\r'))* (EndOfLine {newline();})?
			{_ttype = ANTLR_USE_NAMESPACE(antlr)Token::SKIP;}
		)
	|	
		('a'..'z'|'A'..'Z'|'_')
		('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
	;
